package com.tsj.spzx.service.Impl;

import cn.hutool.core.collection.CollectionUtil;
import com.tsj.spzx.utils.AuthContextThreadLocalUtil;
import com.tsj.spzx.Utils.MenuTreeListUtil;
import com.tsj.spzx.exception.TsjException;
import com.tsj.spzx.mapper.SysMenuMapper;
import com.tsj.spzx.mapper.SysRoleMenuMapper;
import com.tsj.spzx.model.entity.system.SysMenu;
import com.tsj.spzx.model.vo.common.ResultCodeEnum;
import com.tsj.spzx.model.vo.system.SysMenuVo;
import com.tsj.spzx.service.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;

@Service
public class SysMenuServiceImpl implements SysMenuService {

    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    public List<SysMenu> findNodes() {
        // 1、先查询到所有菜单
        List<SysMenu> menuList = sysMenuMapper.findNodes();

        // 进行判断，如果菜单信息为空，直接返回
        if (CollectionUtil.isEmpty(menuList)) {
            throw new TsjException(ResultCodeEnum.DATA_ERROR);
        }

        // 2、调用自己写的Util方法，去将返回的所有菜单信息List列表转换成符合前端要求的List型列表
        List<SysMenu> menuTreeList = MenuTreeListUtil.buildTreeList(menuList);
        return menuTreeList;
    }

    @Transactional
    @Override
    public void saveSysMenu(SysMenu sysMenu) {
        sysMenuMapper.saveSysMenu(sysMenu);

        // 新添加一个菜单，那么此时就需要将该菜单所对应的父级菜单设置为半开
        // 避免bug：当我们先为一个角色分配了该菜单的所有子菜单，那么存储到数据库中该菜单的is_half就会是0，此时如果我们再为该菜单分配一个子菜单，
        // 那么这个角色会默认选中这个新添加的子菜单，所以当我们在添加子菜单时，需要将父菜单的is_half设置为1
        updateSysRoleMenuIsHalf(sysMenu) ;
    }

    private void updateSysRoleMenuIsHalf(SysMenu sysMenu) {
        // 获取其父节点
        SysMenu parentMenu = sysMenuMapper.getParentById(sysMenu.getParentId());
        // 如果父节点不为空，将其is_half设置为1
        if (parentMenu != null){
            sysRoleMenuMapper.updateSysRoleMenuIsHalf(parentMenu.getId());
            // 递归调用
            updateSysRoleMenuIsHalf(parentMenu);
        }
    }

    @Override
    public void updateSysMenu(SysMenu sysMenu) {
        sysMenuMapper.updateSysMenu(sysMenu);
    }

    @Override
    public void removeById(Long id) {
        // 1、删除菜单时，需要判断当前菜单是否还有子菜单，如果有子菜单，则不允许删除
        int childrenNum = sysMenuMapper.countById(id);
        if (childrenNum > 0){
            throw new TsjException(ResultCodeEnum.NODE_ERROR);
        }

        // 2、没有子节点，可以直接删除
        sysMenuMapper.removeById(id);
    }

    @Override
    public List<SysMenuVo> getMenusByUserId() {
        // 根据用户id获取用户菜单
        // 1、先获取用户id，在拦截器中获取过，存放在了ThreadLocal中
        Long userId = AuthContextThreadLocalUtil.get().getId();
        // 2、根据用户id获取到他的所有菜单
        // 多表关联查询 sys_role_menu表 sys_menu表 sys_user_role表
        List<SysMenu> roleMenuList = sysMenuMapper.getMenusByUserId(userId);
        // 将菜单变成树形结构
        List<SysMenu> menuTreeList = MenuTreeListUtil.buildTreeList(roleMenuList);
        // 将该List<SysMenu>变成我们要返回的List<SysMenuVo>
        List<SysMenuVo> menuVoList = build(menuTreeList);
        return menuVoList;
    }

    private List<SysMenuVo> build(List<SysMenu> menus) {
        // 将List<SysMenu>变成List<SysMenuVo>
        List<SysMenuVo> sysMenuVoList = new LinkedList<>();
        for (SysMenu sysMenu : menus){
            SysMenuVo sysMenuVo = new SysMenuVo();
            sysMenuVo.setTitle(sysMenu.getTitle());
            sysMenuVo.setName(sysMenu.getComponent());
            // 先获取sysMenu的子菜单集合
            List<SysMenu> children = sysMenu.getChildren();
            if (CollectionUtil.isNotEmpty(children)){
                sysMenuVo.setChildren(build(children));
            }
            sysMenuVoList.add(sysMenuVo);
        }
        return sysMenuVoList;
    }
}
